package com.wzdigit.wms.wms.service.order;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wzdigit.framework.Shift;
import com.wzdigit.framework.utils.RedisUtil;
import com.wzdigit.mes.basic.api.BasicDataItemDetailApi;
import com.wzdigit.mes.basic.api.BasicParamApi;
import com.wzdigit.mes.basic.api.BasicSimpleCodeRuleApi;
import com.wzdigit.mes.basic.dto.DataItemDetailDTO;
import com.wzdigit.mes.basic.dto.ParamDetailDTO;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.domain.asn.AsnDtl;
import com.wzdigit.wms.basic.domain.asn.AsnDtlGoods;
import com.wzdigit.wms.basic.domain.asn.AsnHeader;
import com.wzdigit.wms.basic.domain.basic.Sku;
import com.wzdigit.wms.basic.domain.basic.Warehouse;
import com.wzdigit.wms.basic.domain.dtos.inventory.SnInforDto;
import com.wzdigit.wms.basic.domain.dtos.inventory.UpdateInventoryInputDto;
import com.wzdigit.wms.basic.domain.inventory.Goods;
import com.wzdigit.wms.basic.domain.inventory.GoodsPkg;
import com.wzdigit.wms.basic.domain.inventory.InvTrans;
import com.wzdigit.wms.basic.domain.inventory.Lotno;
import com.wzdigit.wms.basic.domain.oqc.QmsOqc;
import com.wzdigit.wms.basic.domain.order.TrsnDtl;
import com.wzdigit.wms.basic.domain.order.TrsnDtlGoods;
import com.wzdigit.wms.basic.domain.order.TrsnHeader;
import com.wzdigit.wms.basic.enums.*;
import com.wzdigit.wms.basic.mapper.core.basic.SkuMapper;
import com.wzdigit.wms.basic.mapper.core.basic.WarehouseMapper;
import com.wzdigit.wms.basic.mapper.core.order.AsnDtlGoodsMapper;
import com.wzdigit.wms.basic.mapper.core.order.AsnDtlMapper;
import com.wzdigit.wms.basic.mapper.core.order.AsnHeaderMapper;
import com.wzdigit.wms.basic.service.code.InventoryService;
import com.wzdigit.wms.basic.service.code.LotnoService;
import com.wzdigit.wms.basic.util.HttpSessionUtil;
import com.wzdigit.wms.wms.service.core.*;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.BeanUtil;
import net.dreamlu.mica.core.utils.CollectionUtil;
import net.dreamlu.mica.core.utils.StringUtil;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ReceiveGoodsService {
    private static final String MDIC_HZ="MDIC_HZ";

    @Value("${mycache.prefix.downLine}")
    private String downLineKey;

    @Autowired
    AsnManagerService asnManagerService;

    @Autowired
    SkuMapper skuMapper;

    @Autowired
    QmsOqcManagerService qmsOqcManagerService;

    @Autowired
    GoodsService goodsService;

    @Autowired
    LotnoService lotnoService;

    @Autowired
    WarehouseMapper whsMapper;

    @Autowired
    private AsnHeaderMapper asnHeaderMapper;
    @Autowired
    private AsnDtlMapper asnDtlMapper;
    @Autowired
    private AsnDtlGoodsMapper asnDtlGoodsMapper;

    @Autowired
    TrsnManagerService trsnManagerService;

    @Reference(version = "${dubbo.consumers.basic.simple.code.rule.api:1.0.0}", check = false)
    BasicSimpleCodeRuleApi basicSimpleCodeRuleApi;

    @Reference(version = "${dubbo.consumers.basic.data.item.detail.api:1.0.0}", check = false, timeout = 300000)
    BasicDataItemDetailApi basicDataItemDetailApi;

    @Reference(version = "${dubbo.providers.basic.BasicParam.api:1.0.0}", check = false)
    BasicParamApi basicParamApi;

    @Autowired
    InventoryService inventoryService;

    final String palletNoRuleCode = "virtualPalletCode";
    final String asnRuleCode = "ASN_R01";
    final String ASN_R96 = "ASN_R96";
    final String trsnRuleCode = "TRSN_ORDER";
    final String line2WhsDataItemCode = "LINE_TO_WHS";


    /**
     * 收货
     *
     * @param snList   sn清单
     * @param userName 操作人
     * @return 返回结果
     * @throws Exception 
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Result receive(List<String> snList, String userName, String dataSource,String asnType) throws Exception {
        //1.生成虚拟卡板号
        String pkgCode = this.basicSimpleCodeRuleApi.GenerateCode(this.palletNoRuleCode);
        Result result = this.receive(snList, pkgCode, userName, dataSource,asnType);
        //干掉缓存
        String key =downLineKey+userName;
        RedisUtil.delete(key);

        return result;
    }

    /**
     * 收货
     * 老版本：sn写入Goods表(mes->qms->wms，有检验单)  收货是根据检验单分组创建入库单
     *
     * @param snList   sn列表
     * @param pkgCode  包装编码
     * @param userName 操作人
     * @throws Exception 
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Result receiveOld(List<String> snList, String pkgCode, String userName, String type) throws Exception {

        if (snList.size() != snList.stream().distinct().count()) {
            Shift.fatal("传入重复数据!");
        }
        //1. 获取sn信息
        List<Goods> goodsList = this.goodsService.selectListByListSn(snList);
        if (goodsList.size() != snList.size()) {
            List<String> existSn = goodsList.stream().map(Goods::getGoodsSn).distinct().collect(Collectors.toList());
            List<String> notExistSn = snList.stream().filter(t -> !existSn.contains(t)).collect(Collectors.toList());
            Shift.fatal("以下sn未同步:[" + String.join(",", notExistSn) + "]");
        }
        if (goodsList.stream().filter(t -> t.getStatus() == GoodsStatusEnum.CREATE.getCode()).count() < goodsList.size()) {
            List<String> existSn = goodsList.stream().filter(t -> t.getStatus() != GoodsStatusEnum.CREATE.getCode()).map(Goods::getGoodsSn).collect(Collectors.toList());
            Shift.fatal("以下sn状态不在建档状态:[" + String.join(",", existSn) + "]");
        }
        if (goodsList.stream().map(Goods::getPrdWo).distinct().count() > 1) {
            Shift.fatal("不同工单不允许打包在一个包装内!");
        }
        if (goodsList.stream().anyMatch(t -> "".equals(t.getLotno()))) {
            Shift.fatal("含未生成批次号的SN记录!");
        }
        for (Goods goods : goodsList) {
            if ("".equals(goods.getInspNo())) {
                Shift.fatal(String.format("sn[%s]没有找到送检单!", goods.getGoodsSn()));
            }
        }
        //2. 获取 送检单信息
        List<String> oqcBills = goodsList.stream().map(Goods::getInspNo).distinct().collect(Collectors.toList());
        List<QmsOqc> qmsOqcs = this.qmsOqcManagerService.selectListByOqcs(oqcBills);
        if (qmsOqcs.size() == 0) {
            Shift.fatal("找不到送检单信息:[" + String.join(",", oqcBills) + "]");
        }
        if (qmsOqcs.size() < oqcBills.size()) {
            List<String> existSn = qmsOqcs.stream().map(QmsOqc::getOqc).distinct().collect(Collectors.toList());
            List<String> notExistSn = oqcBills.stream().filter(t -> !existSn.contains(t)).collect(Collectors.toList());
            Shift.fatal("找不到送检单信息:[" + String.join(",", notExistSn) + "]");
        }
        Result result = this.asnManagerService.existReceiveGoods(oqcBills, snList);
        if (!result.isFlag()) {
            Shift.fatal("以下条码已经收过货了:[" + result.getMessage() + "]");
        }
        TrsnHeader trsnHeader = null;
        int rowIndex = 0;
        // 添加栈板信息
        GoodsPkg newPkg = this.setGoodsPkg(pkgCode, userName);
        this.goodsService.getGoodsPkgMapper().insert(newPkg);
        newPkg.setUrl(String.format("%s_0", newPkg.getGoodsPkgId()));
        this.goodsService.getGoodsPkgMapper().updateUrlByGoodsPkgId(newPkg.getGoodsPkgId(), newPkg.getUrl());
        System.out.println(newPkg.getGoodsPkgId()+">>>>>>>>>>");
        // 按送检单创建/修改送货单 , 交易单 , 库存处理
        for (QmsOqc qmsOqc : qmsOqcs) {
            // 获取 goods 详细信息
            List<Goods> nowGoodsList = goodsList.stream().filter(t -> t.getInspNo().equals(qmsOqc.getOqc())).collect(Collectors.toList());
            //定义 ASN 单信息
            AsnHeader asnHeader = new AsnHeader();
            AsnDtl asnDtl = new AsnDtl();
            List<AsnDtlGoods> asnDtlGoodsList = new ArrayList<>();
            //调用asn单据处理
            this.handleAsn(qmsOqc, nowGoodsList, userName, asnHeader, asnDtl, asnDtlGoodsList, type);
            //定义 TRSN 单信息
            rowIndex++;
            //调用Trsn单据处理
            trsnHeader = this.handleTrsn(asnHeader, asnDtl, asnDtlGoodsList, trsnHeader, rowIndex);
            // 修改sn的父节点信息
            List<String> nowSnList = nowGoodsList.stream().map(Goods::getGoodsSn).collect(Collectors.toList());
            this.goodsService.getGoodsMapper().updatePkgIdAndStatusAndWhsIdBySnList(nowSnList, newPkg.getGoodsPkgId(), GoodsStatusEnum.WAIT_UP.getCode(), trsnHeader.getWhsId(), userName);
            for (Goods item : nowGoodsList) {
                item.setPkgId(newPkg.getGoodsPkgId());
                item.setWhsId(asnHeader.getToWhs());
                item.setStatus(GoodsStatusEnum.WAIT_UP.getCode());
                item.setModifyUser(userName);
                item.setStockInDate(new Date());
                item.setModifyTime(new Date());
            }
            //库存处理
            this.handleInventory(asnHeader, asnDtl, nowGoodsList, trsnHeader.getNoteNo(), rowIndex, userName);
        }
        return new Result(true, "操作成功!");
    }

    /*
     收货
     新版本：sn写入Goods表(mes->wms)，根据sku_id&工单&线体&时间生成送货单而非送检单
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Result receive(List<String> snList, String pkgCode, String userName, String dataSource,String asnType) throws Exception {
        if (snList.size() != snList.stream().distinct().count()) {
            Shift.fatal("传入重复数据!");
        }
        //获取goods信息
        List<Goods> goodsList = this.goodsService.selectListByListSn(snList);
        if (goodsList.size() != snList.size()) {
            List<String> existSn = goodsList.stream().map(Goods::getGoodsSn).distinct().collect(Collectors.toList());
            List<String> notExistSn = snList.stream().filter(t -> !existSn.contains(t)).collect(Collectors.toList());
            Shift.fatal("以下sn未同步:[" + String.join(",", notExistSn) + "]");
        }
        if (goodsList.stream().filter(t -> t.getStatus() == GoodsStatusEnum.CREATE.getCode()).count() < goodsList.size()) {
            List<String> existSn = goodsList.stream().filter(t -> t.getStatus() != GoodsStatusEnum.CREATE.getCode()).map(Goods::getGoodsSn).collect(Collectors.toList());
            Shift.fatal("以下sn状态不在建档状态:[" + String.join(",", existSn) + "]");
        }
        if (goodsList.stream().map(Goods::getPrdWo).distinct().count() > 1) {
            Shift.fatal("不同工单不允许打包在一个包装内!");
        }
        if (goodsList.stream().anyMatch(t -> "".equals(t.getLotno())||t.getLotno()==null)) {
            Shift.fatal("含未生成批次号的SN记录!");
        }
        if (goodsList.stream().anyMatch(t -> "".equals(t.getMfgLine())||t.getMfgLine()==null)) {
            Shift.fatal("含未生成制造工厂的SN记录!");
        }

        //获取码垛下线频率
        ParamDetailDTO paramDetailDTO = basicParamApi.getByCode(MDIC_HZ);
        String rateStr=paramDetailDTO.getSystemParamValue();
        Integer rate =- Integer.valueOf(rateStr);
        //截止时间：当前时间前推rateStr分钟
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE,rate);
        Date closeTime = calendar.getTime();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        log.info("截止时间>>>>>>>>>"+sdf.format(closeTime));

        //生成栈板信息
        GoodsPkg newPkg = this.setGoodsPkg(pkgCode, userName);
        this.goodsService.getGoodsPkgMapper().insert(newPkg);
        newPkg.setUrl(String.format("%s_0", newPkg.getGoodsPkgId()));
        this.goodsService.getGoodsPkgMapper().updateUrlByGoodsPkgId(newPkg.getGoodsPkgId(), newPkg.getUrl());
        //根据产品、线体分组
        Map<String, List<Goods>> goodsMap = goodsList.stream().collect(
                Collectors.groupingBy(t -> t.getMfgLine() + "#" +
                        t.getSkuId(), Collectors.toList()));
        for (List<Goods> mapGoodsList : goodsMap.values()) {
            List<String> mapSnList = mapGoodsList.stream().map(t -> t.getGoodsSn()).collect(Collectors.toList());
            Goods mapGoods = mapGoodsList.get(0);
            //校验sn上是否收货
            List<String> receiveSnList = asnManagerService.searchIsReceive(mapGoods.getMfgLine(),
                    mapGoods.getSkuId(), mapGoods.getPrdWo(), mapSnList);
            if (CollectionUtil.isNotEmpty(receiveSnList)){
                Shift.fatal("以下条码已经收过货了:[" + StringUtil.join(receiveSnList,",") + "]");
            }
            AsnDtl asnDtl=new AsnDtl();
            //查询是否有截止时间往后的符合条件的收货单
            AsnHeader asnHeader=asnHeaderMapper.searchRecieveHeader(mapGoods.getMfgLine(),
                    mapGoods.getSkuId(), mapGoods.getPrdWo(),closeTime,AsnHeaderStatusEnum.PARTRECEIVE.code,asnType);
            if (asnHeader==null){
                Sku sku = this.skuMapper.selectById(mapGoods.getSkuId());
                //生成新的收货单
                DataItemDetailDTO line2WhsItem = this.basicDataItemDetailApi.getDataItemDetailByPCodeAndName(this.line2WhsDataItemCode, mapGoods.getMfgLine());
                if (line2WhsItem == null) {
                    Shift.fatal("数据字典没有配置线体[" + mapGoods.getMfgLine() + "]对应的中转仓!");
                }
                Warehouse warehouse = this.whsMapper.selectOneByWhsCode(line2WhsItem.getRemark());
                if (warehouse == null) {
                    Shift.fatal("没有找到中转仓[" + line2WhsItem.getRemark() + "]信息!");
                }
                Integer toWhsId = warehouse.getWhsId();
                String asnNo="";
                if (AsnTypeEnum.R01.equals(asnType)){
                    asnNo=this.basicSimpleCodeRuleApi.GenerateCode(this.asnRuleCode);
                }else {
                    asnNo=this.basicSimpleCodeRuleApi.GenerateCode(this.ASN_R96);
                }
                asnHeader = setAsnHeader(mapGoods, userName, toWhsId,asnNo);
                asnHeader.setDataSource(dataSource);
                asnHeader.setAsnType(asnType);
                asnHeader.setUdf1(mapGoods.getPrdWo());
                asnHeader.setUdf2(mapGoods.getMfgLine());
                asnDtl = setAsnDetail(asnHeader, mapGoodsList.get(0), sku, userName);
                this.asnManagerService.addAsn(asnHeader, asnDtl);
            }else {
                //向符合的收货单添加sn
                asnDtl= asnDtlMapper.selectList(new QueryWrapper<AsnDtl>()
                        .eq("ASN_HEADER_ID", asnHeader.getAsnHeaderId())).get(0);
            }
            AsnDtlStatusEnum asnDtlStatus = AsnDtlStatusEnum.PARTRECEIVE;
            AsnHeaderStatusEnum asnHeaderStatus = AsnHeaderStatusEnum.PARTRECEIVE;
            BigDecimal nowQty = mapGoodsList.stream().map(Goods::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);
            asnHeader.setStatus(asnHeaderStatus.getCode());
            asnDtl.setStatus(asnDtlStatus.getCode());
            //修改送货单明细的送货数量 & 状态
            this.asnManagerService.getAsnDtlService().getMapper().plusRecQtyAndOrderQtyById(
                    asnDtl.getAsnDtlId(),
                    nowQty,
                    asnDtlStatus.getCode(),//状态
                    userName
            );
            //添加送货单的货品信息
            List<AsnDtlGoods> asnDtlGoodsList = this.setAsnDtlGoodsList(mapGoodsList, userName, asnDtl);
            for (AsnDtlGoods item : asnDtlGoodsList) {
                this.asnManagerService.getAsnDtlGoodsService().getMapper().insert(item);
            }
            //记录入库凭证
            TrsnHeader trsnHeader=null;
            trsnHeader = this.handleTrsn(asnHeader, asnDtl, asnDtlGoodsList, trsnHeader, 0);
            //修改sn
            for (Goods item : mapGoodsList) {
                item.setPkgId(newPkg.getGoodsPkgId());
                item.setWhsId(asnHeader.getToWhs());
                item.setStatus(GoodsStatusEnum.WAIT_UP.getCode());
                item.setModifyUser(userName);
                item.setStockInDate(new Date());
                item.setModifyTime(new Date());
            }
            this.goodsService.getGoodsMapper().updatePkgIdAndStatusAndWhsIdBySnList(mapSnList, newPkg.getGoodsPkgId(), GoodsStatusEnum.WAIT_UP.getCode(), trsnHeader.getWhsId(), userName);

            //增加库存
            this.handleInventory(asnHeader, asnDtl, mapGoodsList, trsnHeader.getNoteNo(), 0, userName);

        }

//        Shift.fatal("/////////////////");

        return new Result(true, "操作成功!");
    }

    private void handleInventory(AsnHeader asnHeader, AsnDtl asnDtl, List<Goods> goodsList, String noteNo, int rowIndex, String userName) throws Exception {
        List<UpdateInventoryInputDto> list = new ArrayList<>();

        Map<String, List<Goods>> collect = goodsList.stream()
                .collect(Collectors.groupingBy(t ->
                                t.getWhsId() + "#" + t.getLocId() + "#" + t.getOwner() + "#" + t.getSkuId() + "#" + t.getFactory() + "#" + t.getVendorId() + "#" + t.getLotno() + "#" + t.getInvAttr() + "#" + t.getQaStatus() + "#",
                        Collectors.toList()));

        for (String key : collect.keySet()) {
            List<Goods> goodsCollect = collect.get(key);
            UpdateInventoryInputDto input = new UpdateInventoryInputDto();
            input.setWhsId(asnDtl.getWhsId());
            input.setOwner(asnHeader.getOwner());
            input.setSkuId(goodsCollect.get(0).getSkuId());
            input.setFactory(asnHeader.getFactory());
            input.setVendorId(asnHeader.getVendorId());
            input.setLotNo(goodsCollect.get(0).getLotno());
            input.setInvAttr(goodsCollect.get(0).getInvAttr());
            input.setQaStatus(goodsCollect.get(0).getQaStatus());
            input.setQty(goodsCollect.stream().map(Goods::getQty).reduce(BigDecimal.ZERO, BigDecimal::add));
            input.setUnit(goodsCollect.get(0).getUnit());
            input.setOperator(userName);
            list.add(input);
        }
        for (UpdateInventoryInputDto input : list) {
            InvTrans log = new InvTrans();
            log.setOpCode(OpCodeEnum.RECEIVE.getCode());
            log.setDocType(asnHeader.getAsnType());
            log.setDocNo(asnDtl.getAsnNo());
            log.setDocLineNo(asnDtl.getAsnLineNo());
            log.setTrsnNo(noteNo);
            log.setTrsnLineNo(String.valueOf(rowIndex));
            log.setStatus(InvTransStatusEnum.FINISHED.getCode());
            log.setTransTime(new Date());
            log.setOperator(input.getOperator());
            log.setTransQty(input.getQty());
            log.setCreateTime(new Date());
            log.setModifyTime(new Date());
            log.setCreateUser(input.getOperator());
            log.setModifyUser(input.getOperator());

            this.inventoryService.inventoryIn(input, log);
        }
    }

    private TrsnHeader handleTrsn(AsnHeader asnHeader, AsnDtl asnDtl, List<AsnDtlGoods> asnDtlGoodsList, TrsnHeader trsnHeader, int rowIndex) {
        if (trsnHeader == null)
            trsnHeader = this.setTrsnHeader(asnHeader);
        TrsnDtl trsnDtl = this.setTrsnDtl(asnHeader, asnDtl, asnDtlGoodsList, rowIndex);
        List<TrsnDtlGoods> trsnDtlGoodsList = this.setTrsnDtlGoods(trsnDtl, asnDtlGoodsList);
        this.trsnManagerService.insertTrsnInfo(trsnHeader, trsnDtl, trsnDtlGoodsList);
        return trsnHeader;
    }

    /**
     * 处理送货单信息
     *
     * @param qmsOqc            oqc单据信息
     * @param goodsList         sn清单信息
     * @param userName          操作人
     * @param r_asnHeader       收货单头
     * @param r_asnDtl          收货单明细
     * @param r_asnDtlGoodsList 收货sn信息
     */
    private void handleAsn(QmsOqc qmsOqc, List<Goods> goodsList, String userName, AsnHeader r_asnHeader, AsnDtl r_asnDtl, List<AsnDtlGoods> r_asnDtlGoodsList, String type) {
        //1. 获取 货品信息
        Sku sku = this.skuMapper.selectById(goodsList.get(0).getSkuId());
        //2. 根据送检单获取送货单
        AsnHeader asnHeader;
        AsnDtl asnDtl = this.asnManagerService.getAsnDtlService().selectOneByInspNo(qmsOqc.getOqc());
        if (asnDtl == null) {
            //1. 获取 中转仓
            DataItemDetailDTO line2WhsItem = this.basicDataItemDetailApi.getDataItemDetailByPCodeAndName(this.line2WhsDataItemCode, goodsList.get(0).getMfgLine());
            if (line2WhsItem == null) {
                Shift.fatal("数据字典没有配置线体[" + goodsList.get(0).getMfgLine() + "]对应的中转仓!");
            }
            Warehouse warehouse = this.whsMapper.selectOneByWhsCode(line2WhsItem.getRemark());
            if (warehouse == null) {
                Shift.fatal("没有找到中转仓[" + line2WhsItem.getRemark() + "]信息!");
            }
            Integer toWhsId = warehouse.getWhsId();
            //创建信息
            asnHeader = this.setAsnHeader(goodsList.get(0), userName, toWhsId,this.basicSimpleCodeRuleApi.GenerateCode(this.asnRuleCode));
            asnHeader.setDataSource(type);

            asnDtl = this.setAsnDetail(asnHeader, goodsList.get(0), sku, userName);
            this.asnManagerService.addAsn(asnHeader, asnDtl);
        } else {
            asnHeader = this.asnManagerService.getAsnHeaderService().getMapper().selectById(asnDtl.getAsnHeaderId());
        }
        //判断质检状态
        AsnDtlStatusEnum asnDtlStatus = AsnDtlStatusEnum.PARTRECEIVE;
        AsnHeaderStatusEnum asnHeaderStatus = AsnHeaderStatusEnum.PARTRECEIVE;
        BigDecimal nowQty = goodsList.stream().map(Goods::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (qmsOqc.getStatus() == QmsOqcStatusEnum.CHECK_ACCESS.getCode()
                || qmsOqc.getStatus() == QmsOqcStatusEnum.CHECK_CONVICTED_BACK.getCode()
        ) {
            //已处理
            BigDecimal allQty = asnDtl.getRcvQty().add(nowQty);
            if (allQty.compareTo(qmsOqc.getSubmitInspQty()) == 0) {
                asnDtlStatus = AsnDtlStatusEnum.WHOLERECEIVE;
                asnHeaderStatus = AsnHeaderStatusEnum.FINISH;
            }
        }
        asnHeader.setStatus(asnHeaderStatus.getCode());
        asnDtl.setStatus(asnDtlStatus.getCode());
        //4. 修改送货单送货数量 / 状态
        this.asnManagerService.getAsnDtlService().getMapper().plusRecQtyAndOrderQtyById(
                asnDtl.getAsnDtlId(),
                nowQty,
                asnDtlStatus.getCode(),//状态
                userName
        );
        //5. 修改送货单状态
        this.asnManagerService.getAsnHeaderService().getMapper().updateStatusById(asnHeader.getAsnHeaderId(),
                asnHeaderStatus.getCode(),
                userName);
        //6. 添加送货单  货品清单
        List<AsnDtlGoods> asnDtlGoodsList = this.setAsnDtlGoodsList(goodsList, userName, asnDtl);
        for (AsnDtlGoods item : asnDtlGoodsList) {
            this.asnManagerService.getAsnDtlGoodsService().getMapper().insert(item);
        }
        BeanUtil.copy(asnHeader, r_asnHeader);
        BeanUtil.copy(asnDtl, r_asnDtl);
        r_asnDtlGoodsList.addAll(asnDtlGoodsList);
    }

    private GoodsPkg setGoodsPkg(String pkgCode, String userName) {
        GoodsPkg goodsPkg = new GoodsPkg();
        goodsPkg.setPkgSn(pkgCode);
        goodsPkg.setPkgLevel(1);
        goodsPkg.setPkgCategory("PALLET");
        goodsPkg.setPkgType(10);
        goodsPkg.setFatherPkgId(0);
        goodsPkg.setIsLeaf(BooleanEnum.TRUE.getCode());
        goodsPkg.setUrl(String.format("%s_0", goodsPkg.getGoodsPkgId()));
        goodsPkg.setCreateTime(new Date());
        goodsPkg.setModifyTime(new Date());
        goodsPkg.setCreateUser(userName);
        goodsPkg.setModifyUser(userName);
        return goodsPkg;
    }

    /*赋值 TrsnHeader*/
    private TrsnHeader setTrsnHeader(AsnHeader asnHeader) {
        TrsnHeader item = new TrsnHeader();
        item.setNoteNo(basicSimpleCodeRuleApi.GenerateCode(trsnRuleCode));
        item.setNoteType(TrsnNoteTypeEnum.IN_STORAGE.getCode()); //凭证类型
        item.setOwner(asnHeader.getOwner());
        item.setFactory(asnHeader.getFactory());
        item.setWhsId(asnHeader.getToWhs());
        item.setVendorId(asnHeader.getVendorId());
        item.setFmDoc(asnHeader.getAsnNo()); //来源单据
        item.setStatus(TrsnHeaderStatusEnum.CMP.getCode());
        item.setCreateTime(new Date());
        item.setModifyTime(new Date());
        item.setModifyUser(asnHeader.getModifyUser());
        item.setCreateUser(asnHeader.getModifyUser());
        return item;
    }

    /*赋值 TrsnDtl*/
    private TrsnDtl setTrsnDtl(AsnHeader asnHeader, AsnDtl asnDtl, List<AsnDtlGoods> asnDtlGoodsList, int rowIndex) {
        TrsnDtl item = new TrsnDtl();
        item.setNoteLineNo(String.valueOf(rowIndex));
        item.setInvUpdateFlag(TrsnDtlInvUpdateFlagEnum.IN.getCode());
        item.setFmDoc(asnDtl.getAsnNo());
        item.setFmDocLine(asnDtl.getAsnLineNo());
        item.setSkuId(asnDtl.getSkuId());
        item.setQty(asnDtlGoodsList.stream().map(AsnDtlGoods::getQty).reduce(BigDecimal.ZERO, BigDecimal::add));
        item.setUnit(asnDtl.getUnit());

        item.setQaStatus(asnDtl.getQaStatus());

        item.setInvAttr(asnDtl.getInvAttr());
        item.setLotAttr1(asnDtl.getLotAttr1());
        item.setLotAttr2(asnDtl.getLotAttr2());
        item.setLotAttr3(asnDtl.getLotAttr3());
        item.setLotAttr4(asnDtl.getLotAttr4());
        item.setLotAttr5(asnDtl.getLotAttr5());
        item.setLotAttr6(asnDtl.getLotAttr6());
        item.setLotAttr7(asnDtl.getLotAttr7());
        item.setLotAttr8(asnDtl.getLotAttr8());
        item.setLotAttr9(asnDtl.getLotAttr9());
        item.setLotAttr10(asnDtl.getLotAttr10());
        item.setLotAttr11(asnDtl.getLotAttr11());
        item.setLotAttr12(asnDtl.getLotAttr12());
        item.setStatus(TrsnDtlStatusEnum.CMP.getCode());
        item.setCreateTime(new Date());
        item.setModifyTime(new Date());
        item.setModifyUser(asnHeader.getModifyUser());
        item.setCreateUser(asnHeader.getModifyUser());
        return item;
    }

    /*赋值 List<TrsnDtlGoods>*/
    private List<TrsnDtlGoods> setTrsnDtlGoods(TrsnDtl trsnDtl, List<AsnDtlGoods> asnDtlGoodsList) {
        List<TrsnDtlGoods> list = new ArrayList<>();
        for (AsnDtlGoods dtlGoods : asnDtlGoodsList) {
            TrsnDtlGoods item = new TrsnDtlGoods();
            item.setTrsnDtlId(trsnDtl.getTrsnDtlId());
            item.setGoodsId(dtlGoods.getGoodsId());
            item.setGoodsSn(dtlGoods.getGoodsSn());
            item.setQaStatus(dtlGoods.getQaStatus());
            item.setQty(dtlGoods.getQty());
            item.setComments("");
            item.setStatus(TrsnDtlGoodsStatusEnum.RECEIVED.getCode());
            item.setQaStatus(dtlGoods.getQaStatus());
            item.setCreateUser(trsnDtl.getModifyUser());
            item.setModifyUser(trsnDtl.getModifyUser());
            item.setCreateTime(new Date());
            item.setModifyTime(new Date());
            list.add(item);
        }
        return list;
    }

    /**
     * 赋值 asnHeader
     *
     * @param goodsItem
     * @param userName
     * @param toWhsId
     * @return
     */
    private AsnHeader setAsnHeader(Goods goodsItem, String userName, Integer toWhsId,String asnNo) {
        AsnHeader asnHeader = new AsnHeader();
        asnHeader.setAsnNo(asnNo);  //单号
        asnHeader.setAsnType(AsnTypeEnum.R01.getCode());
        asnHeader.setPriority(0);
        asnHeader.setOwner(goodsItem.getOwner());
        asnHeader.setAsnCreateTime(new Date());
        asnHeader.setExpectArriveTime1(new Date());
        asnHeader.setFactory(goodsItem.getFactory());
        asnHeader.setToWhs(toWhsId); //中转仓
        asnHeader.setVendorId(goodsItem.getVendorId());
        asnHeader.setPoNo(goodsItem.getPoNo());
        asnHeader.setDataSource("ERP");
        asnHeader.setReleaseStatus(BooleanEnum.FALSE.getCode());
        asnHeader.setAsnPrintFlag(BooleanEnum.FALSE.getCode());
        asnHeader.setQcStatus(QcStatusEnum.已创建质检单.getCode());  //判定结果
        asnHeader.setSnScan(BooleanEnum.FALSE.getCode());
        asnHeader.setRcvOverFlag(BooleanEnum.FALSE.getCode());
        asnHeader.setStatus(AsnHeaderStatusEnum.PARTRECEIVE.getCode());
        asnHeader.setCreateUser(userName);
        asnHeader.setModifyUser(userName);
        asnHeader.setCreateTime(new Date());
        asnHeader.setModifyTime(new Date());
        return asnHeader;
    }

    /**
     * 赋值 asnDetail
     *
     * @param asnHeader
     * @param goodsItem
     * @param sku
     * @param userName
     * @return
     */
    private AsnDtl setAsnDetail(AsnHeader asnHeader,
                                Goods goodsItem,
                                Sku sku,
                                String userName) {
        //1. 获取 goods 的批次属性值
        Lotno lotInfo = this.lotnoService.selectByLotno(goodsItem.getLotno());
        if (lotInfo == null) {
            Shift.fatal("没有找到批次属性信息!");
        }
        AsnDtl asnItem = new AsnDtl();
        asnItem.setAsnNo(asnHeader.getAsnNo());
        asnItem.setAsnLineNo("1");

        asnItem.setPoNo(goodsItem.getPoNo());

        asnItem.setSkuId(sku.getSkuId());
        asnItem.setSkuDesc(sku.getDescCn());
        asnItem.setSkuDescEn(sku.getDescEn());

        asnItem.setLotno(goodsItem.getLotno());

        asnItem.setOrderQty(BigDecimal.ZERO);
        asnItem.setOrderQtyEa(BigDecimal.ZERO);

        asnItem.setRcvQty(BigDecimal.ZERO);
        asnItem.setRcvQtyEa(BigDecimal.ZERO);

        asnItem.setUnit(sku.getBaseUnit());
        asnItem.setInvAttr(goodsItem.getInvAttr());

        asnItem.setRcvTime(new Date());
        asnItem.setRcvLocId(null);
        asnItem.setPlanLocId(null);

        asnItem.setReserveLocFlag(null);
        asnItem.setInvAttr(goodsItem.getInvAttr());
        asnItem.setInvType(null);

        asnItem.setWhsId(asnHeader.getToWhs());

        asnItem.setQcStatus(QcStatusEnum.已创建质检单.getCode());
        asnItem.setQaStatus(QaStatusEnum.WAIT.getCode());

        asnItem.setInspNo(goodsItem.getInspNo());
        asnItem.setSoNo(goodsItem.getSoNo());
        asnItem.setSoLineNo(goodsItem.getSoItem());

        asnItem.setLotAttr1(lotInfo.getLotAttr1());
        asnItem.setLotAttr2(lotInfo.getLotAttr2());
        asnItem.setLotAttr3(lotInfo.getLotAttr3());
        asnItem.setLotAttr4(lotInfo.getLotAttr4());
        asnItem.setLotAttr5(lotInfo.getLotAttr5());
        asnItem.setLotAttr6(lotInfo.getLotAttr6());
        asnItem.setLotAttr7(lotInfo.getLotAttr7());
        asnItem.setLotAttr8(lotInfo.getLotAttr8());
        asnItem.setLotAttr9(lotInfo.getLotAttr9());
        asnItem.setLotAttr10(lotInfo.getLotAttr10());
        asnItem.setLotAttr11(lotInfo.getLotAttr11());
        asnItem.setLotAttr12(lotInfo.getLotAttr12());
        asnItem.setDataSource("ERP");

        asnItem.setStatus(AsnDtlStatusEnum.CREATE.getCode());
        asnItem.setCreateUser(userName);
        asnItem.setModifyUser(userName);
        asnItem.setCreateTime(new Date());
        asnItem.setModifyTime(new Date());
        return asnItem;
    }

    /**
     * @param listGoods
     * @param userName
     * @param asnItem
     * @return
     */
    private List<AsnDtlGoods> setAsnDtlGoodsList(List<Goods> listGoods, String userName, AsnDtl asnItem) {
        List<AsnDtlGoods> listAsnDtlGoods = new ArrayList<>();
        for (Goods goods : listGoods) {
            AsnDtlGoods item = new AsnDtlGoods();
            item.setAsnDtlId(asnItem.getAsnDtlId());
            item.setGoodsId(goods.getGoodsId());
            item.setGoodsSn(goods.getGoodsSn());
            item.setQaStatus(goods.getQaStatus());
            item.setQty(goods.getQty());
            item.setComments("");
            item.setStatus(AsnDtlGoodsStatusEnum.HAS_RECEIVE.getCode());
            item.setCreateUser(userName);
            item.setModifyUser(userName);
            item.setCreateTime(new Date());
            item.setModifyTime(new Date());
            listAsnDtlGoods.add(item);
        }
        return listAsnDtlGoods;
    }

    /**
     * @param sn
     * @return
     */

    public Result<List<SnInforDto>> scan(String sn,HttpServletRequest servletRequest) {
        List<SnInforDto> snInforDtos = goodsService.selectSnInfosBySn(sn, SnScanTypeEnum.SELECT_SN);
        if (snInforDtos.size() == 0) {
            Shift.fatal(String.format("没有找到sn[%s]的信息!", sn));
        }
        for (SnInforDto item : snInforDtos) {
            if (item.getWhsId() != null)
                Shift.fatal(String.format("当前SN[%s]已经交收!", sn));
            if (item.getOwner() == null || "".equals(item.getOwner()))
                Shift.fatal(String.format("当前SN[%s]货主为空!", sn));
/*            if (item.getInspNo() == null || "".equals(item.getInspNo()))
                Shift.fatal(String.format("当前SN[%s]送检单为空!", sn));*/
            if (item.getFactory() == null || "".equals(item.getFactory()))
                Shift.fatal(String.format("当前SN[%s]组织为空!", sn));
//            if (item.getPoNo() == null || "".equals(item.getPoNo()))
//                Shift.fatal(String.format("当前SN[%s]PO为空!", sn));
            if (item.getSoNo() == null || "".equals(item.getSoNo()))
                Shift.fatal(String.format("当前SN[%s]销售订单为空!", sn));
            if (item.getSoItem() == null || "".equals(item.getSoItem()))
                Shift.fatal(String.format("当前SN[%s]销售订单行号为空!", sn));
            if (!item.getStatus().equals(GoodsStatusEnum.CREATE.getCode()))
                Shift.fatal(String.format("当前SN[%s]不为建档状态!", sn));
        }

        //加个缓存
        String loginName = HttpSessionUtil.getLoginName(servletRequest);
        String key = downLineKey + loginName;
        List<SnInforDto> snInforDtoList = getCacheSnInforDtoList(key,servletRequest);
        if (snInforDtoList!=null) {
            //累加
            if (snInforDtoList.size()>0) {
                for (SnInforDto snInforDto : snInforDtos) {
                    if (!snInforDtoList.contains(snInforDto)) {
                        snInforDtoList.add(snInforDto);
                    }
                }
                RedisUtil.set(key, snInforDtoList);
            }

        }else {
            //新增
            RedisUtil.set(key, snInforDtos);
        }

        return new Result<>(snInforDtos);
    }

    /**
     * 获取缓存
     *
     * @param servletRequest
     * @param servletResponse
     * @return
     */
    public Result<List<SnInforDto>> getCache(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {

        String loginName = HttpSessionUtil.getLoginName(servletRequest);
        String key = downLineKey + loginName;
        List<SnInforDto> snInforDtoList = getCacheSnInforDtoList(key,servletRequest);

        Result<List<SnInforDto>> result = new Result<>();
        result.setData(snInforDtoList);
        return result;
    }

    /**
     * 获取缓存
     * @param key
     * @param servletRequest
     * @return
     */
    private List<SnInforDto> getCacheSnInforDtoList(String key,HttpServletRequest servletRequest) {
        Object val = RedisUtil.get(key);
        return (List<SnInforDto>) val;
    }

    /**
     * 删除缓存
     * @param servletRequest
     * @param servletResponse
     * @return
     */
    public Result deleteCache(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
        String loginName = HttpSessionUtil.getLoginName(servletRequest);
        String key =downLineKey+loginName;
        RedisUtil.delete(key);
        Result result = new Result();
        return result;
    }
}





























